﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using BciMethods;
using DataAcquisition;
using DataAcquisition.TransferObjects;
using BciUtils;

namespace tpu_bci
{
    public partial class DataRecordForm : Form
    {
        private const int PreparationTime = 5;
        private const int EpochTime = 10;
        private const int RestTime = 3;
        private const int EpochCount = 40;

        private static readonly string[] classes = new string[] { "LeftHand", "RightHand" };

        private int preparationTime;
        private int epochTime;
        private int restTime;
        private int epochCount;

        private const int Second = 1000;

        private MotorImagery? newMotorImagery;
        private bool isStarted = false;

        private Random random = new Random();
        private Thread recordControThread;
        private EegReceiver eegReceiver;
        private EegDataWriter writer;

        private AutoResetEvent waitHandle;

        public DataRecordForm()
        {
            InitializeComponent();

            this.preparationTime = PreparationTime;
            this.epochTime = EpochTime;
            this.restTime = RestTime;
            this.epochCount = EpochCount;

            eegReceiver = new EegReceiver();
            eegReceiver.ProcessEegData = ProcessEegData;

            waitHandle = new AutoResetEvent(false);

            this.sessionNameTextBox.Text = "Session " + DateTime.Now.ToString("dd.MM.yyyy hh.mm.ss");
                    
        }

        private void startRecordingButton_Click(object sender, EventArgs e)
        {
            try
            {
                eegReceiver.StartReceiving();
            }
            catch (Exception)
            {
               // MessageBox.Show("Аппаратные проблемы с устройством ЭЭГ");
                //return;
            }
            
            writer = new EegDataWriter(this.sessionNameTextBox.Text);

            BasicInfo basicInfo = eegReceiver.BasicInfo;
            if (basicInfo != null)
            {
                writer.WriteInfo(
                    basicInfo.EegChannelsNumber,
                    basicInfo.EventChannelsNumber,
                    basicInfo.SamplingRate,
                    classes
                );
            }

            this.controlPanel.Visible = false;

            recordControThread = new Thread(RecordData);
            recordControThread.IsBackground = true;
            recordControThread.Start();
        }

        private void ProcessEegData(EegData eegData)
        {
            if (!isStarted)
            {
                return;
            }

            if (newMotorImagery != null)
            {
                writer.WriteClassLabel(newMotorImagery.ToString());
                newMotorImagery = null;
            }

            //Maybe problems here if we cannot finish wrinting previous batch
            //We should use queue to avoid it
            writer.WriteSamples(eegData.Data);
        }

        private void RecordData()
        {
            //preparation for data record session
            ExecuteInGuiThread((Action)delegate()
            {
                this.readyTextBox.Text = "Be ready...";
                this.readyTextBox.Visible = true;
            });
            waitHandle.WaitOne(Second);

            //couting down...
            for (int i = preparationTime; i > 0; i--)
            {
                ExecuteInGuiThread((Action)delegate() 
                {
                    this.readyTextBox.Text = i.ToString();
                });
                waitHandle.WaitOne(Second);
            }

            //Start
            ExecuteInGuiThread((Action)delegate()
            {
                this.readyTextBox.Text = "Start...";
            });
            waitHandle.WaitOne(Second);

            ExecuteInGuiThread((Action)delegate()
            {
                this.readyTextBox.Visible = false;
            });
            //---------------

            isStarted = true;
            //record epochs
            for (int i = 0; i < epochCount; i++)
            {
                int randomNumber = random.NextDouble() >= 0.5 ? 1 : 0;
                //int randomNumber = random.Next(Enum.GetValues(typeof(MotorImagery)).Length);
                MotorImagery motorImagery = 
                    (MotorImagery) Enum.GetValues(typeof(MotorImagery)).GetValue(randomNumber);

                ExecuteInGuiThread((Action)delegate()
                {
                    DisplayMotorCommand(motorImagery);
                });

                newMotorImagery = motorImagery;

                waitHandle.WaitOne(epochTime * Second);

                //rest
                ExecuteInGuiThread((Action)delegate()
                {
                    DisplayMotorCommand(null);
                });

                waitHandle.WaitOne(restTime * Second);
            }

            ExecuteInGuiThread((Action)delegate()
            {
                this.controlPanel.Visible = true;
            });

            isStarted = false;
        }

        private void ExecuteInGuiThread(Delegate method)
        {            
            this.Invoke(method);            
        }

        private void DisplayMotorCommand(MotorImagery? motorImagery)
        {
            switch (motorImagery)
            {
                case MotorImagery.LeftHand:
                    this.leftPictureBox.Visible = true;
                    this.rightPictureBox.Visible = false;
                    break;
                case MotorImagery.RightHand:
                    this.leftPictureBox.Visible = false;
                    this.rightPictureBox.Visible = true;
                    break;
                case null:
                default:
                    this.leftPictureBox.Visible = false;
                    this.rightPictureBox.Visible = false;
                    break;
            }
        }

        private void DataRecordForm_FormClosing(object sender, FormClosingEventArgs e)
        {            
            eegReceiver.StopReceiving();
            if (recordControThread != null)
            {
                recordControThread.Abort();
            }
        }
    }
}
